package com.kgajowy.ast;

import com.kgajowy.envs.ENVS;
import com.kgajowy.envs.ENVSFrame;
import com.kgajowy.expressions.DotExpression;
import com.kgajowy.objects.SBAObject;
import com.kgajowy.objects.SBAStore;
import com.kgajowy.objects.StringObject;
import com.kgajowy.result.BagResult;
import com.kgajowy.result.IntegerResult;
import com.kgajowy.result.QResStack;
import com.kgajowy.result.ReferenceResult;
import com.kgajowy.result.SingleResult;
import com.kgajowy.result.StringResult;

import edu.pjwstk.jps.interpreter.envs.IENVSBinder;
import edu.pjwstk.jps.result.ISingleResult;

import java.util.LinkedList;

public class cw3 {

    public static void dot_operator (SBAStore dbstore) {
        QResStack qres = new QResStack();
        ENVS envs = new ENVS();
        
        // 1. Zainicjalizować dotres = bag()
        envs.init(dbstore.getEntryOID(), dbstore);
        
        BagResult dotres = new BagResult();
        
        // 2. Wykonać eval(q1) i zrobić q1res = QRES.POP()
        qres.push((BagResult) envs.bind("emp") );
               
        // 3. Dla każdego elementu x ze zbioru q1res wykonać:
        for ( ISingleResult s : ((BagResult) qres.pop()).getElements() ) {
            // 3.1. Utworzyć nową sekcję na ENVS
            LinkedList<IENVSBinder> list = new LinkedList<IENVSBinder>();
            
            // 3.2. Wykonać nested(x). Wynik wprowadzić do sekcji utworzonej w poprzednim kroku
            list.addAll(envs.nested(s, dbstore).getElements());
            envs.push(new ENVSFrame(list));
            
            // 3.3. Wykonać eval(q2) i zrobić q2res = QRES.POP()
            qres.push((BagResult) envs.bind("lName") );
            BagResult b = (BagResult) qres.pop();
            
            // 3.5. Zamknąć sekcję ENVS
            envs.pop();
            
            // 4. Zrobić QRES.PUSH(dotres)
            dotres.add(b);
            
        }
        
        System.out.println(dotres.stringme());
    }
//zle
    public static void where_operator(SBAStore dbstore) {
        QResStack qres = new QResStack();
        ENVS envs = new ENVS();
        
        // 1. Zainicjalizować dotres = bag()
        envs.init(dbstore.getEntryOID(), dbstore);
        
        BagResult dotres = new BagResult();
        
        // 2. Wykonać eval(q1) i zrobić q1res = QRES.POP()
        qres.push((BagResult) envs.bind("emp") );
               
        // 3. Dla każdego elementu x ze zbioru q1res wykonać:
        for ( ISingleResult s : ((BagResult) qres.pop()).getElements() ) {
            // 3.1. Utworzyć nową sekcję na ENVS
            LinkedList<IENVSBinder> list = new LinkedList<IENVSBinder>();
            
            // 3.2. Wykonać nested(x). Wynik wprowadzić do sekcji utworzonej w poprzednim kroku
            list.addAll(envs.nested(s, dbstore).getElements());
            envs.push(new ENVSFrame(list));
            
            // 3.3. Wykonać eval(q2) i zrobić q2res = QRES.POP()
            qres.push((BagResult) envs.bind("married") );
            BagResult b = (BagResult) qres.pop();
            
            // 3.4. Jeżeli q2res wynosi true dodać x do whereres
            if ( b.getElements().size() > 0 ) {
                dotres.add(b);
                //poprawione nizej
            }
            
            // 3.5. Zamknąć sekcję ENVS
            envs.pop();
        }
        
        System.out.println(dotres.stringme());
    }
    
    
    
    
    
    
    
    

    public static void nowak_married(SBAStore dbstore) {
        QResStack qres = new QResStack();
        ENVS envs = new ENVS();
        
        envs.init(dbstore.getEntryOID(), dbstore);
        BagResult leftRes = new BagResult();
        BagResult rightRes = new BagResult();
        
        // wybierz tych ktorzy sa w zwiazku malzenskim oraz tych (unia) ktorzy maja na nazwisko Nowak
        // pokaz ich imiona
        
        //
        //  emp where lastName = Nowak
        //
        
        qres.push(new StringResult("lName"));
        qres.push(new StringResult("Nowak"));
        
        StringResult right = (StringResult) qres.pop();
        StringResult left = (StringResult) qres.pop();
        
        qres.push((BagResult) envs.bind("emp") );
               
        for ( ISingleResult s : ((BagResult) qres.pop()).getElements() ) {
            LinkedList<IENVSBinder> list = new LinkedList<IENVSBinder>();
            
            list.addAll(envs.nested(s, dbstore).getElements());
            envs.push(new ENVSFrame(list));

            qres.push((BagResult) envs.bind(left.getValue()) );
            BagResult b = (BagResult) qres.pop();
            
            ReferenceResult ss = (ReferenceResult) s;
            for ( ISingleResult ref : b.getElements() ) {
                ReferenceResult ref2 = (ReferenceResult) ref;
                if (dbstore.hasElementAChild(ss.getOIDValue(), ref2.getOIDValue())) {
                    
                    StringObject obj = (StringObject) dbstore.retrieve(ref2.getOIDValue());
                    if ( obj.getValue().equals(right.getValue())) {
                        rightRes.add(s);
                    }
                    
                }
            }
            envs.pop();
        }
        qres.push(rightRes);
        
        //
        //  emp where married
        //
        qres.push(new StringResult("emp"));
        qres.push(new StringResult("married"));
        
        right = (StringResult) qres.pop();
        left = (StringResult) qres.pop();
        
        qres.push((BagResult) envs.bind(left.getValue()) );
               
        for ( ISingleResult s : ((BagResult) qres.pop()).getElements() ) {
            LinkedList<IENVSBinder> list = new LinkedList<IENVSBinder>();
            
            list.addAll(envs.nested(s, dbstore).getElements());
            envs.push(new ENVSFrame(list));

            qres.push((BagResult) envs.bind(right.getValue()) );
            BagResult b = (BagResult) qres.pop();
            
            ReferenceResult ss = (ReferenceResult) s;
            for ( ISingleResult ref : b.getElements() ) {
                ReferenceResult ref2 = (ReferenceResult) ref;
                //where exists
                
                LinkedList<IENVSBinder> listElemEmp = new LinkedList<IENVSBinder>();
                
                // 3.2. Wykonać nested(x). Wynik wprowadzić do sekcji utworzonej w poprzednim kroku
                listElemEmp.addAll(envs.nested(s, dbstore).getElements());
                envs.push(new ENVSFrame(listElemEmp));
                
                
                if (dbstore.hasElementAChild(ss.getOIDValue(), ref2.getOIDValue())) {
                    
                    //where true   
                    StringObject married = (StringObject)dbstore.retrieve(ref2.getOIDValue());
                    if ( married.getValue().equals("true")) {
                        leftRes.add(s);
                    }
                }
                
                envs.pop();
            }
            envs.pop();
        }
        
        qres.push(leftRes);
        
        rightRes = (BagResult) qres.pop();
        leftRes = (BagResult) qres.pop();
        
        // union
        BagResult union = new BagResult();
        
        for (ISingleResult u1 : rightRes.getElements()) {
            union.add(u1);
        }
        
        for (ISingleResult u1 : leftRes.getElements()) {
            union.add(u1);
        }
        
        System.out.println("emp where married union lname Nowak\n\t" + union.stringme());
        
        qres.push(union);
        qres.push(new StringResult("fName"));

        StringResult rightL = (StringResult) qres.pop();
        BagResult leftL = (BagResult) qres.pop();
        
        BagResult final_res = new BagResult();
        
        for ( ISingleResult s : leftL.getElements() ) {
            // 3.1. Utworzyć nową sekcję na ENVS
            LinkedList<IENVSBinder> list = new LinkedList<IENVSBinder>();
            
            // 3.2. Wykonać nested(x). Wynik wprowadzić do sekcji utworzonej w poprzednim kroku
            list.addAll(envs.nested(s, dbstore).getElements());
            envs.push(new ENVSFrame(list));
            
            // 3.3. Wykonać eval(q2) i zrobić q2res = QRES.POP()
            qres.push((BagResult) envs.bind(rightL.getValue()) );
            BagResult b = (BagResult) qres.pop();
            
            // 3.5. Zamknąć sekcję ENVS
            envs.pop();
            
            // 4. Zrobić QRES.PUSH(dotres)
            final_res.add(b);
            
        }
        System.out.println("emp where married union lname Nowak fname\n\t" + final_res.stringme());
    }
    
    
    
    
    

    
    public static void address_number(SBAStore dbstore) {
        QResStack qres = new QResStack();
    }
    
}
